package com.iteaj.iot.taos;

import com.iteaj.iot.tools.db.DBMeta;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DefaultTaosSqlManager implements TaosSqlManager<TaosHandle>, BeanFactoryAware {

    private BeanFactory beanFactory;

    private JdbcTemplate taosJdbcTemplate;

    private Logger logger = LoggerFactory.getLogger(getClass());
    private Map<Class<?>, SqlContext> sqlContextMap = new ConcurrentHashMap<>(16);
    private Map<String, SqlContext> tableNameAndSqlContextMap = new ConcurrentHashMap<>(16);

    public DefaultTaosSqlManager(BeanFactory beanFactory, JdbcTemplate taosJdbcTemplate) {
        this.beanFactory = beanFactory;
        this.taosJdbcTemplate = taosJdbcTemplate;
    }

    public TaosSqlMeta getDBMeta(Class<?> entityClass) {
        SqlContext sqlContext = sqlContextMap.get(entityClass);
        if(sqlContext == null) {
            synchronized (this) {
                final TaosSqlMeta taosSqlMeta = new TaosSqlMeta(entityClass).build(this.beanFactory);
                if(entityClass == null) {
                    throw new TaosException("["+TaosHandle.class.getSimpleName()+"]对象的返回实体对象必须使用"+STable.class.getSimpleName()+"注解");
                }

                sqlContext = new SqlContext(taosSqlMeta);
                sqlContextMap.put(entityClass, sqlContext);
            }
        }

        return sqlContext.getMeta();
    }

    public TaosSqlMeta getDBMeta(String tableName) {
        return this.tableNameAndSqlContextMap.get(tableName).getMeta();
    }

    @Override
    public DBMeta remove(String tableName) {
        return this.tableNameAndSqlContextMap.remove(tableName).getMeta();
    }

    @Override
    public TaosSqlMeta register(DBMeta meta) {
        if(meta instanceof TaosSqlMeta) {
            SqlContext sqlContext = new SqlContext((TaosSqlMeta) meta);
            this.tableNameAndSqlContextMap.put(meta.getTableName(), sqlContext);
            return sqlContext.getMeta();
        }

        throw new TaosException("只支持["+ TaosSqlMeta.class.getSimpleName()+"]类型对象");
    }

    @Override
    public TaosSqlMeta registerIfAbsent(DBMeta meta) {
        if(!this.tableNameAndSqlContextMap.containsKey(meta.getTableName())) {
            return this.register(meta);
        }

        return null;
    }

    public SqlContext getSqlContext(Class entityClass) {
        SqlContext sqlContext = sqlContextMap.get(entityClass);
        if(sqlContext == null) {
            this.getDBMeta(entityClass);
        }

        return sqlContextMap.get(entityClass);
    }

    public SqlContext getSqlContext(String tableName) {
        SqlContext sqlContext = this.tableNameAndSqlContextMap.get(tableName);
        if(sqlContext == null) {
            throw new TaosException("表["+tableName+"]对应的元对象不存在");
        }

        return sqlContext;
    }

    @Override
    public int batchInsert(Class entityClazz, List<Object> entities) {
        final SqlContext sqlContext = this.getSqlContext(entityClazz);
        return sqlContext.update(entities, taosJdbcTemplate);
    }

    @Override
    public int insert(String tableName, Object entity) {
        SqlContext sqlContext = this.getSqlContext(tableName);
        return sqlContext.update(entity, taosJdbcTemplate);
    }

    @Override
    public int insert(String tableName, Map<String, Object> value) {
        SqlContext sqlContext = this.getSqlContext(tableName);
        return sqlContext.update(value, taosJdbcTemplate);
    }

    @Override
    public int insert(Class entityClazz, Object entity) {
        SqlContext sqlContext = this.getSqlContext(entityClazz);
        return sqlContext.update(entity, taosJdbcTemplate);
    }

    @Override
    public int batchInsert(String tableName, List<Object> entities) {
        SqlContext sqlContext = this.getSqlContext(tableName);
        return sqlContext.update(entities, taosJdbcTemplate);
    }

    @Override
    public int batchInsert(Class entityClazz, List<Object> entities, int size) {
        if(CollectionUtils.isEmpty(entities)) {
            return 0;
        } else if(entities.size() < size) {
            return batchInsert(entityClazz, entities);
        } else {
            int updateIndex = 0;
            int index = entities.size() / size;
            int remain = entities.size() % size;
            index = remain == 0 ? index : index + 1;
            List<Object> objects;
            for(int i=0; i < index; i++) {
                if(i == index - 1) { // 最后一次
                    objects = entities.subList(i * size, entities.size());
                } else {
                    objects = entities.subList(i * size, i * size + size);
                }

                updateIndex += this.batchInsert(entityClazz, objects);
            }

            return updateIndex;
        }
    }

    @Override
    public void execute(Object value, TaosHandle handle) {
        SqlContext sqlContext = this.getSqlContext(value.getClass());
        sqlContext.update(value, handle.taosJdbcTemplate(value));
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

}
